package client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Date;

public class ClientWorker extends Thread{
	private String FILEPATH;
	private ClientManager manager;
	private String serverName;
	private int serverPort;
	private String filename;
	private int connectionType;
	private FileOutputStream fos;
	private boolean finishedOk;
	private String fileSize;
	private File file;
	private Socket socket;
	private long totalFileSize;
	private long timeElapsed;
	public ClientWorker(ClientManager manager, String filepath, String serverName, int serverPort, String filename, int connectionType, String fileSize){
		this.FILEPATH = filepath;
		this.manager = manager;
		this.serverName = serverName;
		this.serverPort = serverPort;
		this.filename = filename;
		this.connectionType = connectionType;
		this.fileSize = fileSize;
	}
	
	public void run(){
		if(executa()){
			synchronized(manager){
				manager.terminou(true, totalFileSize, timeElapsed);
			}
		} else {
			synchronized(manager){
				manager.terminou(false, 0, 0);
			}
		}
	}
	
	private boolean executa(){
		finishedOk = false;
		try{
			socket = new Socket(serverName, serverPort);
			socket.setSoTimeout(10000);
			DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
			if(connectionType == ClientManager.PUT){
				File file = new File(filename);
				long size = file.length();
				dos.writeUTF("PUT");
				dos.writeUTF(file.getName());
				dos.writeLong(size);
				totalFileSize = size;
				
				byte buffer[] = new byte[1024];
				FileInputStream fis = new FileInputStream(file);
				long auxTime = new Date().getTime();
				while(size > 0){
					int max = (int) (size > 1024? 1024 : size);
					int len = fis.read(buffer, 0, max);
					if(len == -1) break;
					size -= len;
					dos.write(buffer, 0, len);
				}
				timeElapsed = (new Date().getTime()) - auxTime;
				
				dos.writeUTF("OK");
				DataInputStream dis = new DataInputStream(socket.getInputStream());
				String result = dis.readUTF();
				if(result.equals("OK")){
					finishedOk = true;
				} else {
					finishedOk = false;
				}
				
				
			} else if(connectionType == ClientManager.GET){
				dos.writeUTF("GET");
				dos.writeUTF(fileSize);
				DataInputStream dis = new DataInputStream(socket.getInputStream());
				String checktype = dis.readUTF();
				if(!checktype.equals("GET")){
					//System.out.println("Unexpected response from server. Finishing program.");
					return false;
				}
				
				String filename = dis.readUTF();
				long size = dis.readLong();
				totalFileSize = size;
				String extension = "";
				int index = filename.lastIndexOf('.');
				if(index != -1){
					extension = filename.substring(index);
					filename = filename.substring(0, index);
				}
				String newName = FILEPATH + File.separator + filename + " - " + new Date().getTime();
				file = new File(newName + extension);
				int count;
				for(count = 2; count < 100 && !file.createNewFile(); count++){
					file = new File(newName + "(" + count + ")" + extension);
				}
				if(count == 100){
					//System.out.println("Too many files with the same name. Aborting operation.");
					return false;
				}
				fos = new FileOutputStream(file);
				byte buffer[] = new byte[1024];
				long auxTime = new Date().getTime();
				while(size > 0){
					int max = (int) (size > 1024l? 1024l : size);
					int len = dis.read(buffer, 0, max);
					if(len == -1) break;
					size -= len;
					fos.write(buffer, 0, len);
				}
				timeElapsed = (new Date().getTime()) - auxTime;
				String verify = dis.readUTF();
				if(!verify.equals("OK")){
					//System.out.println("File was corrupted..");
				} else {
					finishedOk = true;
				}
			}
		} catch(IOException e){
			//System.out.println("Unexpected error");
			e.printStackTrace();
		} finally {
			if(fos != null) try {
				fos.close();
			} catch(Exception e){e.printStackTrace();}
			if(socket != null && !socket.isClosed()) try {
				socket.close();
			} catch(Exception e){}
			if(!finishedOk && file != null && file.exists()) try {
				file.delete();
			} catch(Exception e){}
		}
		return finishedOk;
	}
}
